package com.gitee.wsl.net.base

import com.gitee.wsl.Lib
import com.gitee.wsl.ext.json.defaultJson
import com.gitee.wsl.net.exceptions.Exceptions
import io.ktor.http.HttpStatusCode
import kotlinx.serialization.Serializable

@Serializable
data class CommonJsonResult<T>(
    /**
     * Http status code
     */
    val status: Int,

    /**
     * User defined message code. default is http code when error occurs.
     */
    val code: Int = if (status in 200..299) 0 else status,
    val info: String = "",
    val data: T? = null
) {
    fun checkException() {
        when (status) {
            in 200..299 -> {  }
            //400 -> throw BadRequestException(info.ifBlank { "Unknown error" })
            //401 -> throw Exceptions.Unauthorized()//InvalidAuthorizationException(info.ifBlank { "Unauthorized" })
            //403 -> throw Exceptions.Forbidden()//ForbiddenOperationException(info.ifBlank { "Forbidden" })
            //404 -> throw NotFoundException(info.ifBlank { "Not found" })
            //429 -> throw Exceptions.BadRequest()//TooManyRequestException(info.ifBlank { "Too many request" })
            //500, 502 -> throw Exceptions.//ServerFaultException(info.ifBlank { "Server fault" }, code)
            //501 -> throw Exceptions.NotFound()//NotSupportedException(info.ifBlank { "Not supported" })
            else -> throw Exceptions(HttpStatusCode.fromValue(code))//CommonBusinessException(info.ifBlank { "Unknown error" }, code)
        }
    }

    @Suppress("UNCHECKED_CAST")
    inline fun <reified R: T> toJsonString() = Lib.defaultJson.encodeToString<CommonJsonResult<R>>(this as CommonJsonResult<R>)
}

interface CommonRequest<T> {
    val type: Int
    val data: T

    private data class CommonRequestImpl<T>(
        override val type: Int,
        override val data: T
    ) : CommonRequest<T>

    operator fun <R> invoke(type: Int, data: R): CommonRequest<R> {
        return CommonRequestImpl(type, data)
    }
}

@Serializable
data class ErrorResult(
    val exception: String = "",
    val exceptionFullName: String = "",
    val trace: String = ""
)